package cryptor

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"io"

	"gitee.com/Luna-CY/Golang-Project-Template/internal/errors"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/logger"
)

// SumFileMd5 计算文件的MD5哈希值
func SumFileMd5(file io.Reader) (string, errors.Error) {
	hash := md5.New()

	_, err := io.Copy(hash, file)
	if err != nil {
		logger.SugarLogger(logger.WithStack()).Errorf("IUC_OR.SFM_D5.204519: %v", err)

		return "", errors.New(errors.ErrorTypeServerInternalError, "IUC_OR.SFM_D5.193705", "计算文件哈希值失败")
	}

	return hex.EncodeToString(hash.Sum(nil)), nil
}

// SumFileSha1 计算文件的SHA-1哈希值
func SumFileSha1(file io.Reader) (string, errors.Error) {
	hash := sha1.New()

	_, err := io.Copy(hash, file)
	if err != nil {
		logger.SugarLogger(logger.WithStack()).Errorf("IUC_OR.SFS_A1.324509: %v", err)

		return "", errors.New(errors.ErrorTypeServerInternalError, "IUC_OR.SFS_A1.313711", "计算文件哈希值失败")
	}

	return hex.EncodeToString(hash.Sum(nil)), nil
}

// SumFileSha256 计算文件的SHA-256哈希值
func SumFileSha256(file io.Reader) (string, errors.Error) {
	hash := sha256.New()

	_, err := io.Copy(hash, file)
	if err != nil {
		logger.SugarLogger(logger.WithStack()).Errorf("IUC_OR.SFS_56.444459: %v", err)

		return "", errors.New(errors.ErrorTypeServerInternalError, "IUC_OR.SFS_56.154751", "计算文件哈希值失败")
	}

	return hex.EncodeToString(hash.Sum(nil)), nil
}

// SumFile 计算文件的哈希值
// 同时返回文件的MD5、SHA-1、SHA-256哈希值
func SumFile(file io.Reader) (string, string, string, errors.Error) {
	var md5 = md5.New()
	var sha1 = sha1.New()
	var sha256 = sha256.New()
	var blockSize = 1024

	var bs = make([]byte, 0, blockSize)

	for {
		n, err := file.Read(bs)
		if err != nil {
			if err == io.EOF {
				return hex.EncodeToString(md5.Sum(nil)), hex.EncodeToString(sha1.Sum(nil)), hex.EncodeToString(sha256.Sum(nil)), nil
			}

			logger.SugarLogger(logger.WithStack()).Errorf("IUC_OR.SF_LE.674440 读取文件失败 %v", err)

			return "", "", "", errors.New(errors.ErrorTypeServerInternalError, "IUC_OR.SF_LE.624028", "计算文件哈希值失败")
		}

		md5.Write(bs[:n])
		sha1.Write(bs[:n])
		sha256.Write(bs[:n])

		if n < blockSize {
			break
		}
	}

	return hex.EncodeToString(md5.Sum(nil)), hex.EncodeToString(sha1.Sum(nil)), hex.EncodeToString(sha256.Sum(nil)), nil
}
